<?php

class MuItiIterator implements Iterator {
  var $arr;
  var $depth;
  var $filter;
  var $iterators;
  var $valid;
  var $pos;
  function __construct($arr,$depth,$filter=false){
    //echo "mi:__construct(arr,$depth,".($filter ? $filter[1] : 'NONE' ).")\n";
    $this->arr = $arr;
    $this->depth = $depth;
    $this->filter = $filter;
	$this->rewind();
    //echo "after mi:__construct():".($this->filter ? $this->filter[1] : 'NONE' )."\n";
  }
  
  function _new_iterator($arr) {
    $obj = new ArrayObject( $arr );
    return $obj->getIterator();
  }
  
  function rewind() {
    //echo "mi:rewind():".($this->filter ? $this->filter[1] : 'NONE' )."\n";
	$this->pos = 0;
	$this->iterators[0] = $this->_new_iterator($this->arr);
	$this->valid = $this->_seek_at_level(0);
    //echo "after mi:rewind():".($this->filter ? $this->filter[1] : 'NONE' )."\n";
  }
  
  function current() {
	return $this->iterators[$this->depth-1]->current();
  }
  function key() {
    return $this->pos;
  }
  function next() {
    $this->valid = $this->_seek_at_level($this->depth-1,true);
	if ( $this->valid ) {
	  $this->pos++;
	  return $this->current();
	} else {
      return false;
	}
  }
  function valid() {
    return $this->valid;
  }

  function keys() {
    $key = array();
	for( $level=0; $level<$this->depth; $level++ ) {
	  $key[] =  $this->iterators[$level]->key();
	}
	return $key;
  }

  function _seek_at_level($level,$next=false) {
    //echo "_seek_at_level($level,$next) \n";
	while ( $level >= 0 ) {
	  if ( $next ) $this->iterators[$level]->next();
	  if ( ! $this->iterators[$level]->valid() ) {
	    $level--;  // run out at this level go down one
	    $next = true;
	  } else {
		//echo "trying $level [" . $this->iterators[$level]->key() . "]  (depth:".$this->depth.")\n";
        if ( $level >= $this->depth-1 ) {
			//echo "trying filter: ". ($this->filter? $this->filter[1] : 'NONE') ."\n";
			if ( $this->filter && ! call_user_func($this->filter,$this->key(),$this->current(),$this->keys()) ) {
		      // didn't pass filter, try again at same level
	          $next = true;
			} else {
			  //echo "found at $level keys=" . print_r($this->keys(),true) . "\n";
			  return true;
			}
		} else {
          $subarr = $this->iterators[$level]->current();
	      if ( count($subarr) > 0 ) {  // skip empty sub_arrays
            $level++;
	        $this->iterators[$level] = $this->_new_iterator($subarr);
		    // seek from start of next level up
	        $next = false;
		  } else {
		    // stay at same level, look for next
	        $next = true;
		  }
		}
	  }
	}
	return false;
  }

}



?>